package divinity.animation
{
	import flash.display.MovieClip;
	import flash.events.EventDispatcher;
	import flash.events.Event;
	import divinity.events.WorldEvent;
	
	public class SpeedController extends EventDispatcher
	{
		private var _img:MovieClip;
		private var _world:*; 
		private var _play:Boolean=false;
		private var _first:int;
		private var _last:int;
		private var _framerate:Number=25/1000;
		private var _speed:Number=1;
		private var _frame:int;
		private var _timeframe:int=0;
		private var _forceframe:Number=_framerate;;
		private var _loop:*=null;
		private var _seqObject:Object={name:"",listenName:"",func:null};;
		private var _l:int=0;
		/**
		 * 
		 * <strong>Speed controller</strong> allows user to play animations indipendent of frame rate but still confined by world cycle elapsed time
		 * 
		 * 
		 * 
		 * * @param myWorld sets the controller world definition. World definition is variable that controller adds a WorldEvent listener 
		 * and listens for world cycles for elapsed time.
		 *	@param i is an Movie clip that is to be controlled.
		 *	
		 * 
		 * */
		
		public function SpeedController(myWorld:*,myImage:MovieClip=null)
		{
			
			if(myImage!=null)
			{
				
				img=myImage;
			}
			world=myWorld;
			_world.addEventListener(WorldEvent.CYCLE,cycle);
			
		}
		
		private function donePlay()
		{
		
			var str:String=_seqObject.name;
			
			if(_seqObject.listenName==_seqObject.name)
			{
				var fnc=_seqObject.func;
				dispatchEvent(new Event(str));				
				removeEventListener(str,fnc);
				
			}
			
		}
		private function startPlay()
		{
			dispatchEvent(new Event(Event.INIT));
		
		}
		private function cycle(e:WorldEvent)
		{
			
			if(_play)
			{		
				
				_timeframe+=e.elapsed;
				_frame=_first+Math.round(_forceframe*_timeframe*_speed);
				
				if(_frame>_last)
				{
					_img.gotoAndStop(_last);					
					_timeframe=0;	
					
					if(_loop!=null)
					{
						_frame=_first;
						_l++;
						trace("Loop "+_l);						
					}					
				}
							
				(_l==_loop)?(_play=false,_loop=null,_frame=_last,donePlay()):(_play=true);
				_img.gotoAndStop(_frame);	
			}
		}
		/**
		 * Plays clip from the last frame where it stopped.
		 * */
		public function play()
		{
			_forceframe=_framerate;
			_play=true;
			startPlay()
		}
		/**
		 * Sets the movie current frame at designated frame.COuld be a frame number of frame label
		 * @param frame: int or String
		 * */
		public function stopAt(frame:*)
		{
			
			if(frame is String)
			{
				_img.gotoAndStop(getLabelFrame(frame));
			}
			else
			{
				_img.gotoAndStop(frame);
			}
			
		}
		/**
		 * Stops playing the clip.
		 * */
		public function stop()
		{
			_play=false;
		}
		/**
		 * Plays labeled sequence named sith seq whis is defined in movie clip played.
		 * @param seq is a movie clip label which is to be played
		 * @param tf is a timeframe in milliseconds of animation that is played. If its set to 1000 it plays whole designated animation whit loops  in 1 sec. If there are more than 1 loop, time frame should be modified accordingly. if 1 loop plays 1 sec and you want each loop to play for 1 sec and there are 3 loops, you should put 3x1000
		 * @param lp is how many loops animation is playing. If null animation loops 
		 * */
		public function sequence(seq:String,tf:*=null,lp:*=null)
		{
			_loop=lp;			
			_l=0;
			_seqObject={name:seq}
			var n:int=0;
			_first=getLabelFrame(seq);;
			_last=getLabelFrame(seq+"_end");
				
			if(tf!=null)
			{
				var times:int=_loop
				if(_loop==null)
				{
					times=1;
				}
				var totals:int=(_last-(_first-1))*times;
				_forceframe=totals/tf;
			}
			else
			{
				_forceframe=_framerate;
			}
			_play=true;
			startPlay();
			
		}
		private function getLabelFrame(label:String)
		{
		
			var ret:int;
			var n:int=0;
			while(n<_img.currentLabels.length)
			{				
				if(_img.currentLabels[n].name==label)
				{
					
					ret=_img.currentLabels[n].frame	
					break;
				}
				n++;
			}
			return ret;
		}
		/**
		 * sets MovieClip to be controlled.
		 * */
		public function set img(mc:MovieClip)
		{		
		
			_img=mc;
			_img.gotoAndStop(0);
			_first=1;
			_last=_img.totalFrames;
			
		}
		/**
		 * Sets SpeedController world on which animation depends.
		 * */
		public function set world(w:*)
		{
			_world=w;
			
		}
		/**
		 * Sets SpeedController frame rate on which animation play is based
		 * */
		public function set frameRate(fr:int)
		{			
			_framerate=fr/1000;
			_forceframe=_framerate;
		}
		/**
		 * Sets SpeedController speed of which animation is played
		 * */
		public function set speed(spd:Number)
		{
			_speed=spd;
		}
		/**
		 * 
		 * 
		 * 
		 * */
		override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			_seqObject.listenName=type
			_seqObject.func=listener;
			
			super.addEventListener(type, listener, useCapture, priority, useWeakReference)
		}
	}
}